/*
	Copyright (c) 2010 <copyright holders>
	This source code is licensed under The MIT License,
	see the file LICENSE for details.
	*/

#ifndef PATHFINDER_H
#define PATHFINDER_H

#include <cmath>
#include <vector>

#include "Spatial.hpp"
#include "Landscape.hpp"

namespace spelprog2
{
// Forward declares.
struct LandscapeSpatials;

namespace pathfind
{

// Forward declares.
class SearchNodeList;
class NodeMesh;

// Terrain information struct.
struct TerrainInfo
{
    int height,
        passageWidth,
        hospitality;
};

/** A descriptive class. Used only as a static data object containing
	node connection information. */
class Node
{
friend class NodeGrid;
protected:
    sim::Int index_;
    sim::Int2d position_;
    std::vector<Node*> branches_;
    TerrainInfo terrain_;

public:
    Node(int i, sim::Int2d pos, TerrainInfo &ter);
    Node();

    int getIndex();
    void setIndex(int i);
    sim::Int2d getPosition();
    void setPosition(sim::Int2d pos);
    const std::vector<Node*> &getBranches();
    const TerrainInfo &getTerrainInfo();
    void setTerrainInfo(TerrainInfo &ter);
    
    void addBranch(Node *n);
};

// A container class for a node mesh
class NodeMesh
{
public:
    virtual ~NodeMesh(){};
    
    virtual Node *getNodeAtPosition(sim::Int2d position) const = 0;
    virtual int getNumNodes() const = 0;
};

// An implementation of NodeMesh
class NodeGrid: public NodeMesh
{
protected:
    Node *nodeList_;
    int width_, height_;
    float w_step_, h_step_;
    
public:
    NodeGrid(LandscapeSpatials *landscape, int n_width, int n_height, int steepWall);
    ~NodeGrid();
    
    Node *getNodeAtPosition(sim::Int2d position) const;
    int getNumNodes() const;
};

// A type used for creating a search in a Node mesh. Contains path information.
class SearchNode
{
friend class SearchNodeList;
protected:
    Node *node_;
    SearchNode *parent_;
    sim::Int value_, path_, heuristic_;
    sim::Int state_;
    
    SearchNode(Node *n, SearchNode *p, int h);
    virtual void evaluate();
    
public:
    static const int NO_STATE = 0, CLOSED = 1, OPEN = 2;  
    const std::vector<Node*> &getNodeBranches();

    int getPathLength();
    int getValue();
    int getWeight();
    
    void tracePath(LandscapeSpatials::PointList &path);
};

// Keeps track of all SearchNodes created for a specific search.
class SearchNodeList
{
protected:
    SearchNode **nodeList_;
    sim::Int listSize_;
    std::vector<SearchNode*> openList_;

public:
    SearchNodeList(int size); // We want a one to one representation of the SearchNodes and the Nodes.
                              // This makes it easier to create a SearchNode representation with proper connections.
    ~SearchNodeList();
    
    SearchNode *pushOpenNode(Node *n, SearchNode *p, int h);
    void pushOpenNode(SearchNode *sn);
    SearchNode *popOpenNode(); // TODO: We need this function to be optimized!
                                             // Use priority_queue!
    
    SearchNode *getSearchNode(Node *n, SearchNode *p, int h); //Might be better as a shared pointer
    void closeNode(SearchNode *sn);
    
    void clear();
};

}; // PathFinder
}; // spelprog2

#endif